package com.agger.harmonyosthemeseditor.intelligent;

import ohos.aafwk.ability.DataAbilityHelper;
import ohos.agp.window.service.Window;
import ohos.app.AbilityContext;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.Resource;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Position;
import ohos.media.image.common.Size;
import ohos.os.ProcessManager;

import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

public class GeneralUtil
{
    public static int SliceAnimatorDuration = 240;
    public static float SliceAnimatorDepth = 0.5f;
    public static final String Bundle_Name = "com.agger.harmonyosthemeseditor";
    public static final String VersionCode = "2.0.0.166";
    public static final String appId = "707435296450423616";
    public static final String Fluid_Filter_Base = "{'filter':{'commonFilter':{'system':{'harmonyVersion':'2.0.0'},'groupType':'1|256','curComType': 0x00030004,'faFilter':'{\"localVersionCode\":1000001,\"localMinComPatibleVersionCode\":1000001,\"targetBundleName\":\"com.agger.harmonyosthemeseditor\"}'}},'transferScene':0,'remoteAuthenticationDescription': '','remoteAuthenticationPicture':''}";
    public static final String dawnlighti_header_light = "";
    public static final String dawnlighti_header_dark = "";

    private static final int CACHE_SIZE = 256 * 1024;

    public static DataAbilityHelper createDataAbilityHelper(Context mContext)
    {
        /*DataAbilityHelper dataAbilityHelper;
        if(SystemVersion.getApiVersion() < 7)
            dataAbilityHelper = DataAbilityHelper.creator(mContext);
        else
            dataAbilityHelper = DataAbilityHelper.create(mContext);
        return dataAbilityHelper;*/
        return DataAbilityHelper.creator(mContext);
    }

    public static String getTimeStr()
    {
        Calendar c= Calendar.getInstance();
        String year = Integer.toString(c.get(Calendar.YEAR));
        String month = c.get(Calendar.MONTH)>=9?Integer.toString(c.get(Calendar.MONTH)+1):("0"+ (c.get(Calendar.MONTH) + 1));
        String date = c.get(Calendar.DATE)>=10?Integer.toString(c.get(Calendar.DATE)):("0"+ c.get(Calendar.DATE));
        String hour;
        if(c.get(Calendar.AM_PM) == Calendar.AM)
            hour = c.get(Calendar.HOUR)>=10?Integer.toString(c.get(Calendar.HOUR)):("0"+ c.get(Calendar.HOUR));
        else
            hour = Integer.toString(c.get(Calendar.HOUR)+12);
        String minute = c.get(Calendar.MINUTE)>=10?Integer.toString(c.get(Calendar.MINUTE)):("0"+ c.get(Calendar.MINUTE));
        String second = c.get(Calendar.SECOND)>=10?Integer.toString(c.get(Calendar.SECOND)):("0"+ c.get(Calendar.SECOND));
        return year+month+date+hour+minute+second;
    }

    public static int readBlindBoxVersion(String zippath, Context context)
    {
        try
        {
            String outzippath = context.getCacheDir()+"/temp_blindbox";
            if(new File(outzippath).exists()) FileManager.deleteDirectory(outzippath,true,false);
            new File(outzippath).mkdirs();
            File file = new File(zippath);
            File outFile;
            ZipFile zipFile = new ZipFile(file);
            ZipInputStream zipInput = new ZipInputStream(new FileInputStream(file));
            ZipEntry entry;
            InputStream input;
            OutputStream output;
            while((entry = zipInput.getNextEntry()) != null)
            {
                if(entry.getName().equals("DatabaseStorage/Int/Version"))
                {
                    outFile = new File(outzippath + File.separator + entry.getName());
                    if(!outFile.getParentFile().exists()) {outFile.getParentFile().mkdirs();}
                    if(!entry.isDirectory())
                    {
                        if(!outFile.exists()) {outFile.createNewFile();}
                        else if(outFile.exists()) {outFile.delete();}
                        input = zipFile.getInputStream(entry);
                        output = new FileOutputStream(outFile);
                        int temp;
                        while((temp = input.read())!=-1){output.write(temp);}
                        input.close();
                        output.close();
                    }
                    else
                    {
                        return -1;
                    }
                }
            }
            DatabaseManager.Init(outzippath);
            int returnValue = DatabaseManager.getInt("Version",-1);
            DatabaseManager.Init(context);
            if(new File(outzippath).exists()) FileManager.deleteDirectory(outzippath,true,false);
            return returnValue;
        } catch (Exception e) {return -1;}
    }

    public static class ThemeInfo
    {
        private String mChineseName,mInternationalName,mDesignerName,mVersionCode,mBriefInfo;
        public ThemeInfo(String ChineseName,String InternationalName,String DesignerName,String VersionCode,String BriefInfo)
        {
            mChineseName = ChineseName;
            mInternationalName = InternationalName;
            mDesignerName = DesignerName;
            mVersionCode = VersionCode;
            mBriefInfo = BriefInfo;
        }
        public String getChineseName(){return mChineseName;}
        public String getInternationalName(){return mInternationalName;}
        public String getDesignerName(){return mDesignerName;}
        public String getVersionCode(){return mVersionCode;}
        public String getBriefInfo(){return mBriefInfo;}
    }

    public static ThemeInfo getThemeInfo(String xmlPath)
    {
        File xmlFile = new File(xmlPath);
        try
        {
            FileInputStream in = new FileInputStream(xmlFile);
            byte[] b = new byte[(int) xmlFile.length()];
            in.read(b);
            String xmlText = new String(b);
            in.close();
            String mChineseName = xmlText.substring(xmlText.lastIndexOf("<title-cn>")+10,xmlText.lastIndexOf("</title-cn>"));
            String mInternationalName = xmlText.substring(xmlText.lastIndexOf("<title>")+7,xmlText.lastIndexOf("</title>"));
            String mDesignerName = xmlText.substring(xmlText.lastIndexOf("<designer>")+10,xmlText.lastIndexOf("</designer>"));
            String mVersionCode = xmlText.substring(xmlText.lastIndexOf("<version>")+9,xmlText.lastIndexOf("</version>"));
            String mBriefInfo = xmlText.substring(xmlText.lastIndexOf("<briefinfo>")+11,xmlText.lastIndexOf("</briefinfo>"));
            return new ThemeInfo(mChineseName,mInternationalName,mDesignerName,mVersionCode,mBriefInfo);
        }catch(IOException ex) {return new ThemeInfo("Unknown","Unknown","Unknown","Unknown","Unknown");}
    }

    public static PixelMap getColorPixelMap(int mColor)
    {
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.size = new Size(1,1);
        initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
        initializationOptions.editable = true;
        PixelMap nPixelMap = PixelMap.create(initializationOptions);
        nPixelMap.writePixel(new Position(0,0),mColor);
        return nPixelMap;
    }

    public static void writeRawFileToFile(Context mContext,String rawFileName,String targetFilePath)
    {
        RawFileEntry rawFileEntry = mContext.getResourceManager().getRawFileEntry("entry/resources/rawfile/"+rawFileName);
        File targetFile = new File(targetFilePath);
        if(targetFile.exists()) targetFile.delete();
        try(FileOutputStream output = new FileOutputStream(targetFilePath))
        {
            Resource resource = rawFileEntry.openRawFile();
            byte[] cache = new byte[CACHE_SIZE];
            int len = resource.read(cache);
            while (len != -1) {
                output.write(cache, 0, len);
                len = resource.read(cache);
            }
        }catch(Exception e){e.printStackTrace();}
    }

    public static void writeResourceToFile(Context mContext,int resourceId,String targetFilePath)
    {
        File targetFile = new File(targetFilePath);
        if(targetFile.exists()) targetFile.delete();
        try(FileOutputStream output = new FileOutputStream(targetFilePath))
        {
            InputStream in = mContext.getResourceManager().getResource(resourceId);
            byte[] cache = new byte[CACHE_SIZE];
            int len = in.read(cache);
            while (len != -1) {
                output.write(cache, 0, len);
                len = in.read(cache);
            }
        }catch(Exception e){e.printStackTrace();}
    }

    public static byte[] getFileByte(File file)
    {
        if(file.exists())
        {
            try
            {
                FileInputStream in = new FileInputStream(file);
                byte[] b = new byte[(int) file.length()];
                in.read(b);
                in.close();
                return b;
            }catch(IOException ex)
            {
                return null;
            }
        }else
        {
            return null;
        }
    }

    public static byte[] getRawFileByte(Context mContext,String rawFileName)
    {
        RawFileEntry rawFileEntry = mContext.getResourceManager().getRawFileEntry("entry/resources/rawfile/"+rawFileName);
        try
        {
            Resource resource = rawFileEntry.openRawFile();
            byte[] cache = new byte[resource.available()];
            resource.read(cache);
            resource.close();
            return cache;
        }catch(Exception e){return null;}
    }

    public static byte[] getResourceByte(Context mContext,int resourceId)
    {

        try
        {
            InputStream in = mContext.getResourceManager().getResource(resourceId);
            byte[] b = new byte[(int) in.available()];
            in.read(b);
            in.close();
            return b;
        }catch(Exception ex)
        {
            return null;
        }
    }

    public static PixelMap getPixelMapFromResource(Context mContext,int resourceId)
    {
        InputStream inputStream = null;
        try
        {
            inputStream = mContext.getResourceManager().getResource(resourceId);
            ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
            srcOpts.formatHint = "image/png";
            ImageSource imageSource = ImageSource.create(inputStream, srcOpts);
            ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
            return imageSource.createPixelmap(decodingOptions);
        }catch(IOException | NotExistException e){e.printStackTrace();}
        finally
        {
            if (inputStream != null)
            {
                try {inputStream.close();}
                catch(IOException e){e.printStackTrace();}
            }
        }
        return null;
    }

    public static PixelMap getPixelMapFromRawFile(Context mContext,String rawFileName)
    {
        try
        {
            RawFileEntry rawFileEntry = mContext.getResourceManager().getRawFileEntry("entry/resources/rawfile/"+rawFileName);
            Resource resource = rawFileEntry.openRawFile();
            ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
            srcOpts.formatHint = "image/png";
            ImageSource imageSource = ImageSource.create(resource, srcOpts);
            ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
            return imageSource.createPixelmap(decodingOptions);
        }catch(Exception e){return null;}
    }

    public static PixelMap getPixelMapFromFile(File file)
    {
        InputStream inputStream = null;
        try{
            inputStream = new FileInputStream(file);
            ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
            srcOpts.formatHint = "image/png";
            ImageSource imageSource = ImageSource.create(inputStream, srcOpts);
            ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
            return imageSource.createPixelmap(decodingOptions);
        }catch(Exception e){e.printStackTrace();}
        finally
        {
            if (inputStream != null)
            {
                try {inputStream.close();}
                catch(IOException e){e.printStackTrace();}
            }
        }
        return null;
    }

    //鸿蒙自带的getBundleManager->getBundleInfos需要ohos.permission.GET_BUNDLE_INFO_PRIVILEGED权限
    //申请此权限，需要成为特权应用或系统级别签名，否则直接闪退不可用，这里通过java的反射机制实现！
    public static String GetAllPackageNames()
    {
        try
        {
            Class<?> c_ActivityThread = Class.forName("android.app.ActivityThread");
            Class<?> ContextImpl  = Class.forName("android.app.ContextImpl");
            Class<?> c_Context = Class.forName("android.content.Context");
            Class<?> c_PackageInfo = Class.forName("android.content.pm.PackageInfo");
            Class<?> c_PackageManager = Class.forName("android.content.pm.PackageManager");

            Method m_systemMain = c_ActivityThread.getDeclaredMethod("systemMain");
            Method m_createSystemContext = ContextImpl.getDeclaredMethod("createSystemContext", c_ActivityThread);
            Method m_createPackageContext = c_Context.getMethod("createPackageContext",String.class,int.class);
            Method m_getPackageManager = c_Context.getDeclaredMethod("getPackageManager");
            Method m_getInstalledPackages = c_PackageManager.getDeclaredMethod("getInstalledPackages",int.class);

            m_createSystemContext.setAccessible(true);

            Object object = m_systemMain.invoke(null);
            Object o_createSystemContext = m_createSystemContext.invoke(null, object);
            Object o_createPackageContext = m_createPackageContext.invoke(o_createSystemContext,"com.agger.harmonyosthemeseditor",1|2);
            Object o_getPackageManager = m_getPackageManager.invoke(o_createPackageContext);
            Object o_getInstalledPackages = m_getInstalledPackages.invoke(o_getPackageManager,0);

            List<?> packages = (List<?>)o_getInstalledPackages;

            String returnValue = "";
            for (int i = 0; i < packages.size(); i++)
            {
                Object packageInfo = packages.get(i);
                String appName = (String)c_PackageInfo.getField("packageName").get(packageInfo);
                returnValue += i>=(packages.size()-1)?appName:appName+",";
            }
            return returnValue;
        }catch (Exception ex) {return ex.getMessage();}
    }

    public static ArrayList<String> GetAppsMainAbilityName(Context mContext)
    {
        try
        {
            Class<?> c_ActivityThread = Class.forName("android.app.ActivityThread");
            Class<?> ContextImpl  = Class.forName("android.app.ContextImpl");
            Class<?> c_Context = Class.forName("android.content.Context");
            Class<?> c_PackageInfo = Class.forName("android.content.pm.PackageInfo");
            Class<?> c_PackageManager = Class.forName("android.content.pm.PackageManager");

            Method m_systemMain = c_ActivityThread.getDeclaredMethod("systemMain");
            Method m_createSystemContext = ContextImpl.getDeclaredMethod("createSystemContext", c_ActivityThread);
            Method m_createPackageContext = c_Context.getMethod("createPackageContext",String.class,int.class);
            Method m_getPackageManager = c_Context.getDeclaredMethod("getPackageManager");
            Method m_getInstalledPackages = c_PackageManager.getDeclaredMethod("getInstalledPackages",int.class);

            m_createSystemContext.setAccessible(true);

            Object object = m_systemMain.invoke(null);
            Object o_createSystemContext = m_createSystemContext.invoke(null, object);
            Object o_createPackageContext = m_createPackageContext.invoke(o_createSystemContext,"com.agger.harmonyosthemeseditor",1|2);
            Object o_getPackageManager = m_getPackageManager.invoke(o_createPackageContext);
            Object o_getInstalledPackages = m_getInstalledPackages.invoke(o_getPackageManager,0);

            List<?> packages = (List<?>)o_getInstalledPackages;

            ArrayList<String> returnValue = new ArrayList<>();
            for (Object packageInfo : packages)
            {
                String appName = (String) c_PackageInfo.getField("packageName").get(packageInfo);
                PixelMap pixelMap = mContext.getBundleManager().getAbilityIcon(appName, "MainActivity");
                if (pixelMap != null) returnValue.add("MainActivity");
                else pixelMap = mContext.getBundleManager().getAbilityIcon(appName, "MainAbility");
                if (pixelMap != null) returnValue.add("MainAbility");
                else
                {
                    try {pixelMap = mContext.getBundleManager().getAbilityIcon(appName, mContext.getBundleManager().getModuleMainAbility(appName, "entry").getClassName());} catch (Exception e) {e.printStackTrace();}
                }
                if (pixelMap != null)
                    returnValue.add(mContext.getBundleManager().getModuleMainAbility(appName, "entry").getClassName());
                else {
                    Class<?> c_Intent = Class.forName("android.content.Intent");
                    Class<?> c_Uri = Class.forName("android.net.Uri");
                    Class<?> c_ResolveInfo = Class.forName("android.content.pm.ResolveInfo");
                    Class<?> c_ActivityInfo = Class.forName("android.content.pm.ActivityInfo");
                    Class<?> c_PackageItemInfo = Class.forName("android.content.pm.PackageItemInfo");

                    Constructor ct_Intent = c_Intent.getDeclaredConstructor(String.class, c_Uri);

                    Method m_addCategory = c_Intent.getDeclaredMethod("addCategory", String.class);
                    Method m_queryIntentActivities = c_PackageManager.getDeclaredMethod("queryIntentActivities", c_Intent, int.class);

                    Object localIntent = ct_Intent.newInstance("android.intent.action.MAIN", null);
                    localIntent = m_addCategory.invoke(localIntent, "android.intent.category.LAUNCHER");
                    List<?> appList = (List<?>) m_queryIntentActivities.invoke(o_getPackageManager, localIntent, 0);
                    for (Object resolveInfo : appList)
                    {
                        Object o_ActivityInfo = c_ResolveInfo.getField("activityInfo").get(resolveInfo);
                        String packageStr = (String) c_ActivityInfo.getField("packageName").get(o_ActivityInfo);
                        if (packageStr.equals(appName))
                        {
                            String className = (String) c_PackageItemInfo.getField("name").get(o_ActivityInfo);
                            className = className.substring(className.lastIndexOf(".") + 1);
                            returnValue.add(className);
                            break;
                        }
                    }
                }
                pixelMap = null;
                System.gc();
            }
            return returnValue;
        }catch (Exception e){e.printStackTrace();return null;}
    }

    //鸿蒙自带的getBundleManager->getBundleInfos需要ohos.permission.GET_BUNDLE_INFO_PRIVILEGED权限
    //申请此权限，需要成为特权应用或系统级别签名，否则直接闪退不可用，这里通过java的反射机制实现！
    public static ArrayList<PixelMap> GetAllAppIcons()
    {
        try
        {
            Class<?> c_ActivityThread = Class.forName("android.app.ActivityThread");
            Class<?> ContextImpl  = Class.forName("android.app.ContextImpl");
            Class<?> c_Context = Class.forName("android.content.Context");
            Class<?> c_PackageInfo = Class.forName("android.content.pm.PackageInfo");
            Class<?> c_PackageManager = Class.forName("android.content.pm.PackageManager");
            Class<?> c_ApplicationInfo = Class.forName("android.content.pm.ApplicationInfo");

            Method m_systemMain = c_ActivityThread.getDeclaredMethod("systemMain");
            Method m_createSystemContext = ContextImpl.getDeclaredMethod("createSystemContext", c_ActivityThread);
            Method m_createPackageContext = c_Context.getMethod("createPackageContext",String.class,int.class);
            Method m_getPackageManager = c_Context.getDeclaredMethod("getPackageManager");
            Method m_getInstalledPackages = c_PackageManager.getDeclaredMethod("getInstalledPackages",int.class);
            Method m_loadIcon = c_ApplicationInfo.getMethod("loadIcon",c_PackageManager);

            m_createSystemContext.setAccessible(true);

            Object object = m_systemMain.invoke(null);
            Object o_createSystemContext = m_createSystemContext.invoke(null, object);
            Object o_createPackageContext = m_createPackageContext.invoke(o_createSystemContext,"com.agger.harmonyosthemeseditor",1|2);
            Object o_getPackageManager = m_getPackageManager.invoke(o_createPackageContext);
            Object o_getInstalledPackages = m_getInstalledPackages.invoke(o_getPackageManager,0);

            List<?> packages = (List<?>)o_getInstalledPackages;

            ArrayList<PixelMap> returnValue = new ArrayList<>();
            for (Object packageInfo : packages)
            {
                Object applicationInfo = c_PackageInfo.getField("applicationInfo").get(packageInfo);
                Object appIcon = m_loadIcon.invoke(applicationInfo, o_getPackageManager);
                Object bm = drawableToBitmap(appIcon);
                if (bm != null)
                {
                    PixelMap pixelMap = ImageIntelligent.ResizeImage(BitmaptoPixelMap(bm), 192, 192);
                    if (pixelMap != null)
                        returnValue.add(pixelMap);
                }
            }
            return returnValue;
        }catch (Exception ex) {ex.printStackTrace();return null;}
    }

    public static Object drawableToBitmap(Object drawable)
    {
        try
        {
            Class<?> c_Drawable = Class.forName("android.graphics.drawable.Drawable");
            Class<?> c_Bitmap = Class.forName("android.graphics.Bitmap");
            Class<?> c_Canvas = Class.forName("android.graphics.Canvas");

            Class<Enum> c_Config = null;
            Class<?>[] c_Bitmap_Classes = c_Bitmap.getDeclaredClasses();
            for(Class<?> c : c_Bitmap_Classes)
            {
                if(c.getName().contains("Config"))
                    c_Config = (Class<Enum>)c;
            }

            Constructor ct_Canvas = c_Canvas.getDeclaredConstructor(c_Bitmap);

            Method m_getIntrinsicWidth = c_Drawable.getDeclaredMethod("getIntrinsicWidth");
            Method m_getIntrinsicHeight = c_Drawable.getDeclaredMethod("getIntrinsicHeight");
            Method m_setBounds = c_Drawable.getDeclaredMethod("setBounds",int.class,int.class,int.class,int.class);
            Method m_draw = c_Drawable.getDeclaredMethod("draw",c_Canvas);

            ArrayList<Method> m_createBitmap = new ArrayList<>();
            Method[] methods_Bitmap = c_Bitmap.getDeclaredMethods();
            for(Method m : methods_Bitmap)
            {
                if(m.getName().contains("createBitmap"))
                {
                    m_createBitmap.add(m);
                }
            }
            Object bitmap = null;
            int error = 0;
            for (Method method : m_createBitmap)
            {
                try
                {
                    bitmap = method.invoke(null, m_getIntrinsicWidth.invoke(drawable), m_getIntrinsicHeight.invoke(drawable), Enum.valueOf(c_Config, "ARGB_8888"));
                    break;
                } catch (Exception ex)
                {
                    error++;
                }
            }
            if(error>=m_createBitmap.size()) return null;
            Object canvas = ct_Canvas.newInstance(bitmap);
            m_setBounds.invoke(drawable,0,0,m_getIntrinsicWidth.invoke(drawable), m_getIntrinsicHeight.invoke(drawable));
            m_draw.invoke(drawable,canvas);
            return bitmap;

        }catch (Exception e) {return null;}
    }

    public static PixelMap BitmaptoPixelMap(Object bitmap) throws Exception
    {
        Class<?> c_Bitmap = Class.forName("android.graphics.Bitmap");

        Method m_getWidth = c_Bitmap.getDeclaredMethod("getWidth");
        Method m_getHeight = c_Bitmap.getDeclaredMethod("getHeight");
        Method m_getPixels = c_Bitmap.getDeclaredMethod("getPixels",int[].class, int.class,int.class,int.class,int.class,int.class,int.class);

        int width = (int)m_getWidth.invoke(bitmap);
        int height = (int)m_getHeight.invoke(bitmap);

        int[] pixels = new int[width * height];
        m_getPixels.invoke(bitmap,pixels, 0, width, 0, 0, width, height);

        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.size = new Size(width,height);
        initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
        initializationOptions.editable = true;
        PixelMap nPixelMap = PixelMap.create(initializationOptions);
        for(int h = 0; h < height; h++)
        {
            for(int w = 0; w < width; w++)
            {
                nPixelMap.writePixel(new Position(w,h),pixels[width*h+w]);
            }
        }
        return nPixelMap;
    }

    public static boolean setWindowToMaxRefreshRate(Window window)
    {
        try
        {
            ProcessManager.setThreadPriority(-20);
            Field f_agpWindow = Window.class.getDeclaredField("agpWindow");
            f_agpWindow.setAccessible(true);
            Object agpWindow = f_agpWindow.get(window);
            Class<?> c_AGPWindow = Class.forName("ohos.agp.window.wmc.AGPWindow");
            Field f_mAndroidWindow = c_AGPWindow.getDeclaredField("mAndroidWindow");
            f_mAndroidWindow.setAccessible(true);
            Object mAndroidWindow = f_mAndroidWindow.get(agpWindow);

            Class<?> c_Window = Class.forName("android.view.Window");
            Class<?> c_WindowManager = Class.forName("android.view.WindowManager");
            Class<?> c_Display = Class.forName("android.view.Display");

            Class<?> c_LayoutParams = null;
            Class<?>[] c_WindowManager_all =  c_WindowManager.getDeclaredClasses();
            for(Class<?> c : c_WindowManager_all)
            {
                if(c.getName().endsWith("LayoutParams"))
                    c_LayoutParams = c;
            }

            Class<?> c_Mode = null;
            Class<?>[] c_Display_all =  c_Display.getDeclaredClasses();
            for(Class<?> c : c_Display_all)
            {
                if(c.getName().endsWith("Mode"))
                    c_Mode = c;
            }

            Method m_getAttributes = c_Window.getDeclaredMethod("getAttributes");
            Method m_setAttributes = c_Window.getDeclaredMethod("setAttributes",c_LayoutParams);
            Method m_getWindowManager = c_Window.getDeclaredMethod("getWindowManager");
            Method m_getDefaultDisplay = c_WindowManager.getDeclaredMethod("getDefaultDisplay");
            //Method m_getSupportedRefreshRates = c_Display.getDeclaredMethod("getSupportedRefreshRates");
            Method m_getSupportedModes = c_Display.getDeclaredMethod("getSupportedModes");
            Method m_getRefreshRate = c_Mode.getDeclaredMethod("getRefreshRate");
            Method m_getModeId = c_Mode.getDeclaredMethod("getModeId");

            m_getDefaultDisplay.setAccessible(true);

            Object o_getAttributes = m_getAttributes.invoke(mAndroidWindow);
            Object o_getWindowManager = m_getWindowManager.invoke(mAndroidWindow);
            Object o_getDefaultDisplay = m_getDefaultDisplay.invoke(o_getWindowManager);
            //float[] o_getSupportedRefreshRates = (float[])m_getSupportedRefreshRates.invoke(o_getDefaultDisplay);
            Object o_getSupportedModes = m_getSupportedModes.invoke(o_getDefaultDisplay);

            //float targetRefreshRate = o_getSupportedRefreshRates[0];
            //for(float m : o_getSupportedRefreshRates) targetRefreshRate = Math.max(targetRefreshRate,m);

            float targetRefreshRate = (float)m_getRefreshRate.invoke(Array.get(o_getSupportedModes,0));
            int targetModeId = (int)m_getModeId.invoke(Array.get(o_getSupportedModes,0));
            for(int i=0;i<Array.getLength(o_getSupportedModes);i++)
            {
                float thisRefreshRate = (float)m_getRefreshRate.invoke(Array.get(o_getSupportedModes,i));
                if(thisRefreshRate>targetRefreshRate)
                {
                    targetRefreshRate = thisRefreshRate;
                    targetModeId = (int)m_getModeId.invoke(Array.get(o_getSupportedModes,i));
                }
            }

            //c_LayoutParams.getField("preferredRefreshRate").set(o_getAttributes,targetRefreshRate);
            c_LayoutParams.getField("preferredDisplayModeId").set(o_getAttributes,targetModeId);
            m_setAttributes.invoke(mAndroidWindow,o_getAttributes);
            return true;
        }catch (Exception e)
        {
            e.printStackTrace();
            return false;
        }
    }

    public static final int SOFT_INPUT_ADJUST_NOTHING = 48;
    public static final int SOFT_INPUT_ADJUST_PAN = 32;
    public static final int SOFT_INPUT_ADJUST_RESIZE = 16;
    public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0;
    public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 256;
    public static final int SOFT_INPUT_MASK_ADJUST = 240;
    public static final int SOFT_INPUT_MASK_STATE = 15;
    public static final int SOFT_INPUT_MODE_CHANGED = 512;
    public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;
    public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
    public static final int SOFT_INPUT_STATE_HIDDEN = 2;
    public static final int SOFT_INPUT_STATE_UNCHANGED = 1;
    public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0;
    public static final int SOFT_INPUT_STATE_VISIBLE = 4;

    public static boolean setWindowSoftInputMode(Window window,int mode)
    {
        try
        {
            Field f_agpWindow = Window.class.getDeclaredField("agpWindow");
            f_agpWindow.setAccessible(true);
            Object agpWindow = f_agpWindow.get(window);
            Class<?> c_AGPWindow = Class.forName("ohos.agp.window.wmc.AGPWindow");
            Field f_mAndroidWindow = c_AGPWindow.getDeclaredField("mAndroidWindow");
            f_mAndroidWindow.setAccessible(true);
            Object mAndroidWindow = f_mAndroidWindow.get(agpWindow);
            Class<?> c_Window = Class.forName("android.view.Window");
            Method m_setSoftInputMode = c_Window.getDeclaredMethod("setSoftInputMode",int.class);
            m_setSoftInputMode.invoke(mAndroidWindow,mode);
            return true;
        }catch (Exception e)
        {
            e.printStackTrace();
            return false;
        }
    }

    public static Object getAbilityShellActivity(AbilityContext abilityContext)
    {
        try
        {
            Field f_context = AbilityContext.class.getDeclaredField("context");
            f_context.setAccessible(true);
            Object context = f_context.get(abilityContext);
            Class<?> c_ContextDeal = Class.forName("ohos.app.ContextDeal");
            Field f_activityContext = c_ContextDeal.getDeclaredField("activityContext");
            f_activityContext.setAccessible(true);
            Object activityContext = f_activityContext.get(context);
            return activityContext;
        }catch (Exception e)
        {
            e.printStackTrace();
            return null;
        }
    }

    public static Object getBitmapFromFile(String pathName)
    {
        try
        {
            Class<?> BitmapFactory = Class.forName("android.graphics.BitmapFactory");
            Method decodeFile = BitmapFactory.getMethod("decodeFile",String.class);
            Object bitmap = decodeFile.invoke(null, pathName);
            return bitmap;
        }catch (Exception e)
        {
            e.printStackTrace();
            return null;
        }
    }

    public static boolean addDynamicShortcuts(Object mAndroidContext,String[] mShortCutId,String[] mShortCutLabel,Object[] mIconBitmap)
    {
        try
        {
            Class<?> c_Context = Class.forName("android.content.Context");
            Class<?> c_ShortcutManager = Class.forName("android.content.pm.ShortcutManager");
            Class<?> c_ShortcutInfo = Class.forName("android.content.pm.ShortcutInfo");
            Class<?> c_ShortcutInfo_Builder = null;
            Class<?>[] c_ShortcutInfo_all =  c_ShortcutInfo.getDeclaredClasses();
            for(Class<?> c : c_ShortcutInfo_all)
            {
                if(c.getName().endsWith("Builder"))
                    c_ShortcutInfo_Builder = c;
            }
            Class<?> c_Icon = Class.forName("android.graphics.drawable.Icon");
            Class<?> c_Intent = Class.forName("android.content.Intent");
            Class<?> c_Uri = Class.forName("android.net.Uri");
            Class<?> c_Bitmap = Class.forName("android.graphics.Bitmap");

            Constructor ct_ShortcutInfo = c_ShortcutInfo_Builder.getDeclaredConstructor(c_Context,String.class);
            Constructor ct_Intent = c_Intent.getDeclaredConstructor(String.class,c_Uri);

            Method m_getSystemService = c_Context.getMethod("getSystemService",String.class);
            Method m_setShortLabel = null;
            Method m_setLongLabel = null;
            Method m_setIcon = null;
            Method m_setIntent = null;
            Method[] methods_Builder = c_ShortcutInfo_Builder.getDeclaredMethods();
            for(Method m : methods_Builder)
            {
                if(m.getName().endsWith("setShortLabel"))
                    m_setShortLabel = m;
                else if(m.getName().endsWith("setLongLabel"))
                    m_setLongLabel = m;
                else if(m.getName().endsWith("setIcon"))
                    m_setIcon = m;
                else if(m.getName().endsWith("setIntent"))
                    m_setIntent = m;
            }
            Method m_createWithBitmap = c_Icon.getDeclaredMethod("createWithBitmap",c_Bitmap);
            Method m_parse = c_Uri.getDeclaredMethod("parse",String.class);
            Method m_build = c_ShortcutInfo_Builder.getDeclaredMethod("build");
            Method m_setDynamicShortcuts = null;
            Method[] methods_ShortcutManager = c_ShortcutManager.getDeclaredMethods();
            for(Method m : methods_ShortcutManager)
            {
                if(m.getName().endsWith("setDynamicShortcuts"))
                    m_setDynamicShortcuts = m;
            }
            m_getSystemService.setAccessible(true);

            Object o_ShortcutManager = m_getSystemService.invoke(mAndroidContext, "shortcut");

            ArrayList list = new ArrayList<>();
            for(int i = 0; i < mShortCutId.length; i++)
            {
                Object o_Intent = null;
                if(i==0)
                    o_Intent = ct_Intent.newInstance("android.settings.APPLICATION_DETAILS_SETTINGS",m_parse.invoke(null,"package:com.agger.harmonyosthemeseditor"));
                else if(i==1)
                    o_Intent = ct_Intent.newInstance("android.intent.action.VIEW",m_parse.invoke(null,"appmarket://details?id=com.agger.harmonyosthemeseditor"));

                Object o_Icon = m_createWithBitmap.invoke(null, mIconBitmap[i]);
                Object o_Builder = ct_ShortcutInfo.newInstance(mAndroidContext,mShortCutId[i]);
                Object o_setShortLabel = m_setShortLabel.invoke(o_Builder,mShortCutLabel[i]);
                Object o_setLongLabel = m_setLongLabel.invoke(o_setShortLabel,mShortCutLabel[i]);
                Object o_setIcon = m_setIcon.invoke(o_setLongLabel,o_Icon);
                Object o_setIntent = m_setIntent.invoke(o_setIcon,o_Intent);
                Object o_ShortcutInfo = m_build.invoke(o_setIntent);
                list.add(c_ShortcutInfo.cast(o_ShortcutInfo));
            }
            m_setDynamicShortcuts.invoke(o_ShortcutManager, list);
            return  true;
        }catch (Exception e)
        {
            e.printStackTrace();
            return false;
        }
    }

    public static boolean ReflectClassToFile(Context mContext, String ClassName)
    {
        try
        {
            Class<?> c_AGP = Class.forName(ClassName);
            String af ="";
            for(Field f : c_AGP.getDeclaredFields()) af += ","+f.getName();
            af = af.replaceFirst(",","");
            String am ="";
            for(Method m : c_AGP.getDeclaredMethods()) am += ","+m.getName();
            am = am.replaceFirst(",","");
            String ac ="";
            for(Class<?> c : c_AGP.getDeclaredClasses()) ac += ","+c.getName();
            ac = ac.replaceFirst(",","");
            FileOutputStream out;
            try
            {
                out = new FileOutputStream(mContext.getExternalCacheDir()+"/reflect_"+ClassName+".txt");
                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
                writer.write("Fields:\r\n"+af+"\r\nMethods:\r\n"+am+"\r\nClasses:\r\n"+ac);
                writer.close();
                out.flush();
                out.close();
                return true;
            }catch(IOException ex)
            {
                ex.printStackTrace();
                return false;
            }
        }catch (Exception e)
        {
            e.printStackTrace();
            return false;
        }
    }
}
